package com.xxr.mom.ci.charging.interworking.v2016.accepter.query;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.xxr.mom.ci.charging.device.dto.PileInfo;
import com.xxr.mom.ci.charging.device.dto.StationInfo;
import com.xxr.mom.ci.charging.device.entity.Gun;
import com.xxr.mom.ci.charging.interworking.base.InterfaceAccepter;
import com.xxr.mom.ci.charging.interworking.dto.InterworkingConfigDto;
import com.xxr.mom.ci.charging.interworking.v2016.AbstractV2016Service;
import com.xxr.mom.ci.charging.interworking.vo.ConnectorStatsInfo;
import com.xxr.mom.ci.charging.interworking.vo.EquipmentStatsInfo;
import com.xxr.mom.ci.charging.interworking.vo.StationStatsInfo;
import com.xxr.mom.ci.charging.interworking.vo.api.QueryStationStatsRequest;
import com.xxr.mom.ci.charging.interworking.vo.api.QueryStationStatsResponse;
import com.xxr.mom.ci.charging.service.DeviceStationService;
import com.xxr.mom.ci.common.util.TimeUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 查询统计信息
 * 概述：此查询用于定期获取每个充电站，在某个周期内的统计信息
 * 接口名称：query_station_stats
 * 接口使用方法：由基础设施运营商方实现此接口，数据需求方调用
 *
 * @description: QueryStationStatsService
 * @date: 2024/8/11 18:30
 * @author: natsuki_kining
 * @version: 1.0
 */
@Log4j2
@Service
@RefreshScope
public class QueryStationStatsAccepterService extends AbstractV2016Service<QueryStationStatsRequest, QueryStationStatsResponse> implements InterfaceAccepter<QueryStationStatsRequest, QueryStationStatsResponse> {

    @Autowired
    private DeviceStationService deviceStationService;
    @Autowired
    private MongoTemplate mongoTemplate;

    @Value("${ci.mongo.statistics.collectionName}")
    private String collectionName;

    @Override
    public QueryStationStatsResponse dataHandler(QueryStationStatsRequest request, InterworkingConfigDto configDto) {
        QueryStationStatsResponse response = new QueryStationStatsResponse();
        if (Objects.isNull(request.getStationId()) || Objects.isNull(request.getStartTime()) || Objects.isNull(request.getEndTime())) {
            return response;
        }
        StationInfo stationInfo = deviceStationService.getStationInfo(request.getStationId());
        StationStatsInfo stationStats = new StationStatsInfo();
        stationStats.setStationId(stationInfo.getStationNumber());
        stationStats.setStarTime(TimeUtil.formatLocalDateTime(request.getStartTime()));
        stationStats.setEndTime(TimeUtil.formatLocalDateTime(request.getEndTime()));

        Criteria criteria = Criteria.where("meta.stationId").is(stationInfo.getId())
                .and("startTime")
                .gte(TimeUtil.formatFullLocalDateTime(request.getStartTime().with(LocalTime.MIN)))
                .lte(TimeUtil.formatFullLocalDateTime(request.getEndTime().with(LocalTime.MAX)));

        MatchOperation match = Aggregation.match(criteria);

        ProjectionOperation operation = Aggregation.project("meta.stationId")
                .and("meta.stationId").as("meta.stationId")
                .and("meta.pileId").as("meta.pileId")
                .and("meta.gunId").as("meta.gunId")
                .and("sumPower").as("sumPower");

        GroupOperation group = Aggregation.group("meta.stationId", "meta.pileId", "meta.gunId")
                .sum("sumPower").as("sumPower");

        Aggregation aggregation = Aggregation.newAggregation(match, operation, group);
        AggregationResults<JSONObject> aggregateResult = mongoTemplate.aggregate(aggregation, collectionName, JSONObject.class);
        log.info("aggregateResult:{}", aggregateResult.getMappedResults());

        Integer stationSumPower = 0;
        JSONObject pilePowerJSON = new JSONObject();
        JSONObject gunPowerJSON = new JSONObject();
        if (CollectionUtil.isNotEmpty(aggregateResult.getMappedResults())) {
            for (JSONObject mappedResult : aggregateResult.getMappedResults()) {
                Integer sumPower = mappedResult.getInteger("sumPower");
                stationSumPower += sumPower;
                JSONObject jsonObject = mappedResult.getJSONObject("_id");
                String pileId = jsonObject.getString("pileId");
                String gunId = jsonObject.getString("gunId");
                Integer pilePower = pilePowerJSON.getInteger(pileId);
                if (Objects.isNull(pilePower)) {
                    pilePowerJSON.put(pileId, sumPower);
                } else {
                    pilePower += sumPower;
                    pilePowerJSON.put(pileId, pilePower);
                }
                gunPowerJSON.put(gunId, sumPower);
            }
        }

        List<EquipmentStatsInfo> equipmentStatsInfos = new ArrayList<>();
        List<PileInfo> pileList = stationInfo.getPileList();
        if (CollectionUtil.isNotEmpty(pileList)) {
            for (PileInfo pileInfo : pileList) {
                EquipmentStatsInfo equipmentStatsInfo = new EquipmentStatsInfo();
                equipmentStatsInfo.setEquipmentD(pileInfo.getPileNum());
                Integer pilePower = (Integer) pilePowerJSON.getOrDefault(pileInfo.getId().toString(), 0);
                equipmentStatsInfo.setEquipmentElectricity(new BigDecimal(pilePower).divide(new BigDecimal(1000), 1, RoundingMode.UP).floatValue());

                List<Gun> gunList = pileInfo.getGunList();
                if (CollectionUtil.isNotEmpty(gunList)) {
                    List<ConnectorStatsInfo> connectorStatsInfos = new ArrayList<>();
                    for (Gun gun : gunList) {
                        ConnectorStatsInfo connectorStatsInfo = new ConnectorStatsInfo();
                        connectorStatsInfo.setConnectorId(gun.getConnectorId());
                        Integer gunPower = (Integer) gunPowerJSON.getOrDefault(gun.getId().toString(), 0);
                        connectorStatsInfo.setConnectorElectricity(new BigDecimal(gunPower).divide(new BigDecimal(1000), 1, RoundingMode.UP).floatValue());
                        connectorStatsInfos.add(connectorStatsInfo);
                    }
                    equipmentStatsInfo.setConnectorStatsInfos(connectorStatsInfos);
                }
                equipmentStatsInfos.add(equipmentStatsInfo);
            }
        }

        stationStats.setStationElectricity(new BigDecimal(stationSumPower).divide(new BigDecimal(1000), 1, RoundingMode.UP).floatValue());
        stationStats.setEquipmentStatsInfos(equipmentStatsInfos);
        response.setStationStats(stationStats);
        return response;
    }
}
